home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 2
/
Apprentice-Release2.iso
/
Tools
/
Languages
/
MacMETH 3.2.1
/
Sources
/
MacC2.6
/
M2HM.MOD
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Modula Implementation
|
1992-05-29
|
85.6 KB
|
2,177 lines
|
[
TEXT/MEDT
]
IMPLEMENTATION MODULE M2HM; (* Hermann Seiler 19.4.85 / 10.6.86 / 19.12.91 *)
(* M2HM-implementation for the MOTOROLA MC68000/MC68010 processors. *)
FROM SYSTEM IMPORT
WORD, LONG, SHIFT, VAL;
FROM M2SM IMPORT
Symbol, Mark;
FROM M2DM IMPORT
ObjPtr, StrPtr, StrForm, ConstValue, PDesc,
Object, Structure, Standard,
notyp, undftyp, booltyp, chartyp,
inttyp, bitstyp, dbltyp, realtyp, lrltyp,
proctyp, stringtyp, addrtyp, wordtyp, bytetyp,
WordSize, MinInt, MaxInt,
rngchk, ovflchk;
FROM M2LM IMPORT
pc, maxP, maxM, PutWord, PutLong, FixLink;
CONST
(* Register usage and dedicated registers : *)
(* D-Register pool for expression evaluation. *)
(* D0 = 0; (* freely used, never reserved *)
D1 = 1; (* freely used, never reserved *) *)
D2 = 2; (* D-pool, reserved when used *)
D3 = 3; (* D-pool, reserved when used *)
D4 = 4; (* D-pool, reserved when used *)
D5 = 5; (* D-pool, reserved when used *)
D6 = 6; (* D-pool, reserved when used *)
D7 = 7; (* D-pool, reserved when used *)
(* F-Register pool for floating point arith. *)
(* F0 = 0; (* freely used, never reserved *)
F1 = 1; (* freely used, never reserved *) *)
F2 = 2; (* F2 - F7 reserved when used *)
F7 = 7;
(* A-Register pool for address calculations. *)
A0 = 0; (* A-pool, reserved when used *)
A1 = 1; (* A-pool, reserved when used *)
A2 = 2; (* A-pool, reserved when used *)
A3 = 3; (* A-pool, reserved when used *)
(*
(* Dedicated A-Registers. *)
SB = 4; (* SB = A4 : static base pointer *)
A5 = 5; (* A5 is n e v e r used ! *)
MP = 6; (* MP = A6 : procedure mark *)
SP = 7; (* SP = A7 : active stack pointer *)
(* Instruction size for simple types. *)
byte = 0; word = 1; long = 2;
(* Descriptor size dynamic array parameters. *)
DynArrDesSize = 6;
*)
(* Addressing Mode Categories. *)
DDIR = 0; (* D-Reg. direct *)
ADIR = 10B; (* A-Reg. direct *)
AIDR = 20B; (* (An) *)
AINC = 30B; (* (An)+ *)
ADEC = 40B; (* -(An) *)
AOFF = 50B; (* d16(An) *)
AIDX = 60B; (* d8(An,Rx) *)
XXXW = 70B; (* absolute short *)
XXXL = 71B; (* absolute long *)
PREL = 72B; (* d16(PC) *)
IMM = 74B; (* immediate or SR*)
(* MC68000 instruction mnemonics. *)
(* _____________________________ *)
(* Special purpose. *)
UNLK = 047136B; (* UNLK MP *)
LINK = 047126B; (* LINK MP,#d16 *)
LEASP = 047757B; (* LEA d16(SP),SP *)
INCSP = 050217B; (* ADDQ.L #n,SP *)
DECSP = 050617B; (* SUBQ.L #n,SP *)
MOVEMDEC = 044347B; (* MOVEM.L registers,-(SP) *)
MOVEMINC = 046337B; (* MOVEM.L (SP)+,registers *)
MVEMSP = 027400B; (* MOVE.L ea,-(SP) : push *)
MVESPP = 020037B; (* MOVE.L (SP)+,ea : pop *)
PUSHSB = 027410B + SB; (* MOVE.L SB,-(SP) *)
POPSB = 020137B + SB*1000B; (* MOVEA.L (SP)+,SB *)
MOVEMSTD = 044300B; (* MOVEM.L regs,ea *)
MOVEMLDD = 046300B; (* MOVEM.L ea,regs *)
MOVELIMM = 020074B; (* MOVE.L #imm,ea *)
(* Instructions without operand. *)
NOP = 047161B; RTE = 047163B;
RTS = 047165B; RTD = 047164B; (* MC68010 *)
TRAPV= 047166B; ILL = 045374B;
(* Branches : with a displacement. *)
BRA = 060000B; BSR = 060400B;
BHI = 061000B; BLS = 061400B; BCC = 062000B; BCS = 062400B;
BNE = 063000B; BEQ = 063400B; BVC = 064000B; BVS = 064400B;
BPL = 065000B; BMI = 065400B; BGE = 066000B; BLT = 066400B;
BGT = 067000B; BLE = 067400B;
(* Branches : a register and a displacement. *)
DBT = 050310B; DBRA = 050710B;
DBHI = 051310B; DBLS = 051710B; DBCC = 052310B; DBCS = 052710B;
DBNE = 053310B; DBEQ = 053710B; DBVC = 054310B; DBVS = 054710B;
DBPL = 055310B; DBMI = 055710B; DBGE = 056310B; DBLT = 056710B;
DBGT = 057310B; DBLE = 057710B;
(* Set according to condition an effective address. *)
ST = 050300B;
(* Operand is a specific register. *)
SWAP = 044100B;
EXTW = 044200B; (* EXT.W byte to word *)
EXTL = 044300B; (* EXT.L word to long *)
(* Operand is an effective address. *)
CLR = 041000B; NEG = 042000B;
TST = 045000B; COM = 043000B; (* synonym for NOT *)
JMP = 047300B; JSR = 047200B;
PEA = 044100B; TAS = 045300B;
INC1 = 051000B; (* ADDQ #1,ea *)
DEC1 = 051400B; (* SUBQ #1,ea *)
(* Operand is an immediate value. *)
TRAP = 047100B; (* TRAP #vector *)
EMUF = 170000B; (* Line F *)
EMUA = 120000B; (* Line A *)
(* Operands are a register and an effective address. *)
ADD = 150000B; SUB = 110000B;
CMP = 130000B; EORL = 130400B; (* synonym for exclusive OR *)
ANDL = 140000B; (* synonym for AND *)
ORL = 100000B; (* synonym for inclusive OR *)
CHK = 040600B; LEA = 040700B;
DIVS = 100700B; DIVU = 100300B;
MULS = 140700B; MULU = 140300B;
ADDAL= 150700B; (* ADDA.L ea,An *)
CMPAL= 130700B; (* CMPA.L ea,An *)
SUBAL= 110700B; (* SUBA.L ea,An *)
EXGL = 140500B; (* EXG.L Dn,Dm *)
(* Immediate data within op. and an effective address. *)
ADDQ = 050000B; SUBQ = 050400B;
(* Shift register by count. *)
ASL = 160400B; ASR = 160000B; LSL = 160410B; LSR = 160010B;
ROL = 160430B; ROR = 160030B;
(* Immediate data within extension and an effective address. *)
ADDI = 003000B; ANDI = 001000B; CMPI = 006000B;
EORI = 005000B; ORI = 000000B; SUBI = 002000B;
(* Bit manipulation. *)
BTST = 000400B; BCHG = 000500B; BCLR = 000600B; BSET = 000700B;
(* Move groups. *)
MOVEB = 010000B; (* group 1 *)
MOVEW = 030000B; (* group 3 *)
MOVEL = 020000B; (* group 2 *)
MOVEAW = 030100B; (* MOVEA.W ea,An *)
MOVEAL = 020100B; (* MOVEA.L ea,An *)
MOVEQ = 070000B; (* MOVE.L #imm,Dn *)
MOVEFRSR = 040300B; (* MOVE.W SR,ea *)
MOVETOSR = 043300B; (* MOVE.W ea,SR *)
(* concerning the STATUS register. *)
NBIT = 8; (* negative bit *)
ZBIT = 4; (* zero bit *)
VBIT = 2; (* overflow bit *)
CBIT = 1; (* carry bit *)
(* Left shift constants. *)
LS3 = 10B; LS4 = 20B; LS5 = 40B; LS6 = 100B;
LS7 = 200B; LS8 = 400B; LS9 = 1000B; LS10 = 2000B;
LS11 = 4000B; LS12 = 10000B;
(* System procedure numbers used by the compiler : *)
(* These numbers must correspond with the procedure numbers *)
(* associated with a specific procedure in the definition *)
(* module 'System'. *)
BodyOfSystem = 0; (* 0 is reserved for module body *)
HALTX = 1; (* System.HALTX = HALT-statement *)
MULU32 = 2; (* System.MULU32 = unsigned long MUL *)
DIVU32 = 3; (* System.DIVU32 = unsig. long DIV/MOD *)
MULS32 = 4; (* System.MULS32 = signed long MUL *)
DIVS32 = 5; (* System.DIVS32 = signed long DIV/MOD *)
FADDs = 6; (* System.FADDs = Floating ADD single *)
FSUBs = 7; (* System.FSUBs = Floating SUB single *)
FMULs = 8; (* System.FMULs = Floating MUL single *)
FDIVs = 9; (* System.FDIVs = Floating DIV single *)
FREMs = 10;(* System.FREMs = Floating REM single *)
FCMPs = 11;(* System.FCMPs = Floating CMP single *)
FNEGs = 12;(* System.FNEGs = Floating NEG single *)
FABSs = 13;(* System.FABSs = Floating ABS single *)
FLOATs = 14;(* System.FLOATs = FLOAT single *)
TRUNCs = 15;(* System.TRUNCs = TRUNC single *)
FADDd = 16;(* System.FADDd = Floating ADD double *)
FSUBd = 17;(* System.FSUBd = Floating SUB double *)
FMULd = 18;(* System.FMULd = Floating MUL double *)
FDIVd = 19;(* System.FDIVd = Floating DIV double *)
FREMd = 20;(* System.FREMd = Floating REM double *)
FCMPd = 21;(* System.FCMPd = Floating CMP double *)
FNEGd = 22;(* System.FNEGd = Floating NEG double *)
FABSd = 23;(* System.FABSd = Floating ABS double *)
FLOATd = 24;(* System.FLOATd = FLOAT double *)
TRUNCd = 25;(* System.TRUNCd = TRUNC double *)
FLONG = 26;(* System.FLONG = Floating single to double *)
FSHORT = 27;(* System.FSHORT = Floating double to single *)
VAR
Rpool, Rbusy, Rlock : BITSET;
MoveCode : ARRAY WidType OF CARDINAL;
ShiCode : ARRAY [ Asl .. Ror ] OF CARDINAL;
mask : ARRAY [ 0 .. 32 ] OF LONGINT;
hightyp : StrPtr;
PROCEDURE ProcessorID(VAR id: Processor);
BEGIN
id := "MC68000"
END ProcessorID;
PROCEDURE err(n : CARDINAL);
(* local synonym for M2SM.Mark to save space! *)
BEGIN
Mark(n);
END err;
PROCEDURE Put16(w : WORD);
(* local synonym for M2LM.PutWord to save space! *)
BEGIN
PutWord(w);
END Put16;
PROCEDURE Put32(l : LONGINT);
(* local synonym for M2LM.PutLong to save space! *)
BEGIN
PutLong(l);
END Put32;
PROCEDURE SignedT(VAR x : Item) : BOOLEAN;
(* is x a signed type ? *)
(* Note : Real/LongReal excluded! *)
VAR s : StrPtr;
BEGIN
s := x.typ; (* let x.typ unchanged *)
IF s^.form = Range THEN s := s^.RBaseTyp END;
RETURN (s = inttyp) OR (s = dbltyp)
END SignedT;
PROCEDURE SimpleT(VAR x : Item) : BOOLEAN;
(* is x a simple type of size *)
(* byte/word/long ? *)
(* Note : Real/LongReal excluded! *)
VAR f : StrForm; s : StrPtr; sz : CARDINAL;
BEGIN
s := x.typ; (* let x.typ unchanged *)
IF s^.form = Range THEN s := s^.RBaseTyp END;
f := s^.form; sz := VAL(CARDINAL,s^.size);
RETURN (sz IN {1,2,4}) AND ((f <= Double) OR (f = Pointer) OR
(f = Set) OR (f = ProcTyp) OR (f = Opaque))
END SimpleT;
PROCEDURE RealT(VAR x : Item) : BOOLEAN;
(* is x a floating-point-type ? *)
(* (REAL or LONGREAL) *)
(* Note: floating-point-types are *)
(* NOT considered as simple *)
VAR s : StrPtr;
BEGIN
s := x.typ; (* let x.typ unchanged *)
RETURN (s = realtyp) OR (s = lrltyp)
END RealT;
PROCEDURE SimpleC(VAR x : Item) : BOOLEAN;
(* is x a simple constant of size *)
(* byte/word/long ? *)
(* Note : Real/LongReal excluded! *)
BEGIN
RETURN (x.mode = conMd) & SimpleT(x)
END SimpleC;
PROCEDURE LongVal(VAR x : Item) : LONGINT;
VAR r : LONGINT;
BEGIN r := 0D;
WITH x DO
IF typ^.form = Range THEN typ := typ^.RBaseTyp END;
CASE typ^.form OF
Undef : IF typ^.size = 1 THEN r := LONG(val.Ch)
ELSIF typ^.size = 2 THEN r := LONG(val.C)
ELSE r := val.U END;
| Bool : r := LONG(val.B);
| Char : r := LONG(val.Ch);
| Card, CardInt: r := LONG(val.C);
| Int : r := LONG(val.I);
| Enum : r := LONG(val.Ch);
| Set : r := VAL(LONGINT, val.S);
| LCard,Double : r := val.D;
| Real : r := VAL(LONGINT, val.R);
ELSE r := val.D; (* String, etc. *)
END;
END (*WITH*);
RETURN r
END LongVal;
PROCEDURE WordVal(VAR x : Item) : INTEGER;
VAR r : INTEGER;
BEGIN r := 0;
WITH x DO
IF typ^.form = Range THEN typ := typ^.RBaseTyp END;
CASE typ^.form OF
Undef : IF typ^.size = 1 THEN r := ORD(val.Ch)
ELSIF typ^.size=2 THEN r := VAL(INTEGER,val.C)
ELSE r := VAL(INTEGER, val.U) END;
| Bool : r := ORD(val.B);
| Char : r := ORD(val.Ch);
| Card, CardInt: r := VAL(INTEGER, val.C);
| Int : r := val.I;
| Enum : r := ORD(val.Ch);
| Set : r := VAL(INTEGER, val.S);
| LCard,Double : r := VAL(INTEGER, val.D);
| Real : r := VAL(INTEGER, VAL(LONGINT, val.R));
ELSE r := VAL(INTEGER, val.D); (* String, etc. *)
END;
END (*WITH*);
RETURN r
END WordVal;
PROCEDURE ZeroVal(VAR x : Item) : BOOLEAN;
VAR b : BOOLEAN;
BEGIN b := FALSE;
IF x.mode = conMd THEN
IF x.typ = realtyp THEN b := x.val.R = FLOAT(0)
ELSIF x.typ = lrltyp THEN b := x.val.X = FLOATD(0)
END;
END;
RETURN b
END ZeroVal;
PROCEDURE Iea(fea : CARDINAL) : CARDINAL;
(* invert the 'mode/register' effective address *)
(* to 'register/mode' representation. *)
BEGIN
RETURN (fea MOD 8)*8 + (fea DIV 8)
END Iea;
PROCEDURE Isz(VAR x : Item; VAR fsz : WidType);
(* instruction size for item x : byte/word/long. *)
(* Note : callable only for simple types ! *)
VAR s : INTEGER; sz : WidType;
BEGIN
s := x.typ^.size;
IF s = 1 THEN sz := byte
ELSIF s = 2 THEN sz := word
ELSIF s = 4 THEN sz := long
ELSE sz := long; err(238); (* invalid instruction size *)
END;
fsz := sz
END Isz;
PROCEDURE SetglbMd(VAR x : Item; fadr : INTEGER; ftyp : StrPtr);
(* setup of an item designating a global variable *)
BEGIN
WITH x DO
IF ftyp <> NIL THEN typ := ftyp ELSE typ := undftyp END;
mode := RindMd; mod := 0; lev := 0;
adr := fadr; off := 0; indir := FALSE;
R := SB + 8;
END (*WITH*);
END SetglbMd;
PROCEDURE SetlocMd(VAR x : Item; fadr : INTEGER; ftyp : StrPtr);
(* setup of an item which is relative to the Marker MP *)
BEGIN
WITH x DO
IF ftyp <> NIL THEN typ := ftyp ELSE typ := undftyp END;
mode := RindMd; mod := 0; lev := curLev;
adr := fadr; off := 0; indir := FALSE;
R := MP + 8;
END (*WITH*);
END SetlocMd;
PROCEDURE SetregMd(VAR x : Item; freg : Register; ftyp : StrPtr);
(* setup of an item designating a (long) register. *)
BEGIN
WITH x DO
IF ftyp <> NIL THEN typ := ftyp ELSE typ := undftyp END;
IF freg <= D7 THEN mode := DregMd ELSE mode := AregMd END;
mod := 0; lev := curLev;
adr := 0; off := 0; indir := FALSE;
R := freg; wid := long;
END (*WITH*);
END SetregMd;
PROCEDURE SetstkMd(VAR x : Item; ftyp : StrPtr);
(* setup of an item on top of stack. *)
BEGIN
WITH x DO
IF ftyp <> NIL THEN typ := ftyp ELSE typ := undftyp END;
mode := stkMd; mod := 0; lev := curLev;
adr := 0; off := 0; indir := FALSE;
R := SP + 8;
END (*WITH*);
END SetstkMd;
PROCEDURE SetfltMd(VAR x : Item; fR : Register; ftyp : StrPtr);
BEGIN
WITH x DO
IF ftyp = realtyp THEN (* for single real *)
SetregMd(x, fR, ftyp); (* resulting mode = DregMd! *)
ELSE
typ := ftyp; (* for double real *)
mode := fltMd; FR := fR; (* resulting mode = fltMd ! *)
END;
END (*WITH*);
END SetfltMd;
PROCEDURE SetconMd(VAR x : Item; fval : LONGINT; ftyp : StrPtr);
VAR v : ConstValue;
BEGIN
WITH x DO
IF ftyp <> NIL THEN typ := ftyp ELSE typ := undftyp END;
IF typ^.form = Range THEN typ := typ^.RBaseTyp END;
mode := conMd;
CASE typ^.form OF
Undef : IF typ^.size = 1 THEN v.Ch := VAL(CHAR, fval)
ELSIF typ^.size = 2 THEN v.C := VAL(CARDINAL, fval)
ELSE v.U := fval END;
| Bool : v.B := VAL(BOOLEAN, fval);
| Char : v.Ch := VAL(CHAR, fval);
| Card,
CardInt : v.C := VAL(CARDINAL, fval);
| Int : v.I := VAL(INTEGER, fval);
| Enum : v.Ch := VAL(CHAR, fval);
| LCard : v.D := fval;
| Double : v.D := fval;
| Real : v.R := VAL(REAL, fval);
| Set : v.S := VAL(BITSET, fval);
ELSE v.D := fval; (* String, etc. *)
END;
val := v;
END (*WITH*);
END SetconMd;
PROCEDURE SetbusyReg(r : Register);
BEGIN
IF r IN Rpool THEN INCL(Rbusy,r) END;
END SetbusyReg;
PROCEDURE SaveRegs(VAR save : LONGINT);
(* save the busy registers and return the list *)
(* of the saved registers in 'save'. *)
(* *)
(* Note : the saved registers are NOT released *)
(* ---- and remain busy ! *)
(* SP is never saved nor restored ! *)
(* *)
VAR r, lr : Register; x, reglist, n : CARDINAL;
regs : RECORD
CASE :BOOLEAN OF
TRUE : All : LONGINT
| FALSE: FPU, CPU : CARDINAL
END
END;
BEGIN regs.All := 0D;
(* the global (CPU) registers : *)
x := 1; reglist := 0; r := SP + 8; n := 0;
REPEAT (* from SP-1 downto D0 *)
DEC(r); x := x + x;
IF (r IN Rpool) & (r IN Rbusy) THEN
INC(n); lr := r;
reglist := reglist + x;
END;
UNTIL r = D0;
IF reglist <> 0 THEN
IF n = 1 THEN Put16(MVEMSP + lr)
ELSE Put16(MOVEMDEC); Put16(reglist) END;
END;
regs.CPU := reglist; (* global register set *)
save := regs.All;
END SaveRegs;
PROCEDURE RestoreRegs(save : LONGINT);
(* restore the registers given by 'save'. *)
VAR r, lr : Register; x, reglist, n : CARDINAL;
regs : RECORD
CASE :BOOLEAN OF
TRUE : All : LONGINT
| FALSE: FPU, CPU : CARDINAL
END
END;
BEGIN regs.All := save;
(* the global (CPU) registers : *)
x := 32768; reglist := 0; r := SP + 8; n := 0;
REPEAT (* from SP-1 downto D0 *)
DEC(r); x := x DIV 2; regs.CPU := regs.CPU DIV 2;
IF ODD(regs.CPU) THEN
INC(n); lr := r;
reglist := reglist + x;
END;
UNTIL r = D0;
IF reglist <> 0 THEN
IF n = 1 THEN Put16(MVESPP + Iea(lr)*LS6)
ELSE Put16(MOVEMINC); Put16(reglist) END;
END;
END RestoreRegs;
PROCEDURE Islocked(r : Register) : BOOLEAN;
BEGIN
RETURN (r IN Rlock)
END Islocked;
PROCEDURE ReleaseReg(r : Register);
BEGIN
IF NOT(r IN Rlock) THEN EXCL(Rbusy,r) END;
END ReleaseReg;
PROCEDURE LockReg(r : Register);
BEGIN
INCL(Rlock,r);
END LockReg;
PROCEDURE UnlockReg(r : Register);
(* must be followed by ReleaseReg when r is released *)
BEGIN
EXCL(Rlock,r);
END UnlockReg;
PROCEDURE Release(VAR x : Item);
BEGIN
WITH x DO
IF mode IN ItSet{RindMd,RidxMd,AregMd,DregMd} THEN
IF R IN Rpool THEN ReleaseReg(R) END;
ELSIF (mode = fltMd) THEN
(* temporary solution for SANE *)
IF FR IN Rpool THEN ReleaseReg(FR); ReleaseReg(FR+1) END;
END;
IF mode = RidxMd THEN ReleaseReg(RX) END;
END (*WITH*);
END Release;
PROCEDURE GetReg(VAR r : Register; qual : RegType);
VAR hr, lr : Register;
BEGIN
IF qual = Areg THEN hr := A3 + 8; lr := A0 + 8
ELSE hr := D2; lr := D7 END;
LOOP
IF NOT(hr IN Rbusy) THEN
r := hr; SetbusyReg(hr); EXIT
END;
IF hr = lr THEN
err(215); r := lr; (* register overflow *)
ReleaseReg(lr); EXIT (* avoid endless loop *)
END;
IF qual = Dreg THEN
(* D2 -> D4 -> D6 -> D3 -> D5 -> D7 *)
IF hr = D6 THEN hr := D3
ELSE hr := hr + 2 END
ELSE (* qual = Areg *)
(* A3 -> A2 -> A1 -> A0 *)
hr := hr - 1
END;
END (*LOOP*);
END GetReg;
PROCEDURE GetFReg(VAR r : Register);
(* reserve a pair of adjacent D-Registers. *)
(* Note : only for D-Registers! *)
VAR hr : Register;
BEGIN
hr := D2;
LOOP
IF NOT(hr IN Rbusy) & NOT( (hr+1) IN Rbusy ) THEN
r := hr; SetbusyReg(hr); SetbusyReg(hr+1); EXIT
END;
IF hr = D6 THEN
err(215); r := D6; (* D-Register overflow *)
ReleaseReg(D6); ReleaseReg(D7); (* avoid endless loop *)
EXIT
ELSE
(* (D2,D3) -> (D4,D5) -> (D6,D7) *)
hr := hr + 2
END;
END (*LOOP*);
END GetFReg;
PROCEDURE InitRegs;
BEGIN
Rpool := { D2 .. D7, A0+8 .. A3+8 };
Rlock := { SB+8 .. SP+8 };
Rbusy := Rlock;
END InitRegs;
PROCEDURE CheckRegs;
BEGIN
IF Rbusy <> Rlock THEN
err(234);
Rbusy := Rlock;
END;
END CheckRegs;
PROCEDURE InvertCC(cond : Condition) : Condition;
(* generate the 'inverted' condition. *)
VAR c : CARDINAL;
BEGIN c := ORD(cond);
IF c < 16 THEN
IF ODD(c) THEN DEC(cond) ELSE INC(cond) END;
ELSE
c := c - 16;
c := 15 - c;
c := c + 16;
cond := VAL(Condition, c);
END;
RETURN cond
END InvertCC;
PROCEDURE CodeCC(cond : Condition) : CARDINAL;
(* generate the code for conditions. *)
VAR c : Condition;
BEGIN
CASE cond OF (* for floating point conditions *)
FF : c := F;
| FEQ : c := EQ;
| FGT : c := GT;
| FGE : c := GE;
| FLT : c := CS; (* for SANE *)
| FLE : c := LS; (* for SANE *)
| FGL : c := VS;
| FGLE : c := VC;
| FNGLE : c := VS;
| FNGL : c := VC;
| FNLE : c := GT;
| FNLT : c := GE;
| FNGE : c := CS; (* for SANE *)
| FNGT : c := LS; (* for SANE *)
| FNE : c := NE;
| FT : c := T;
ELSE (* the same condition *)
c := cond;
END (*CASE*);
RETURN VAL(CARDINAL, c)
END CodeCC;
PROCEDURE Jf(cond : Condition; VAR l : CARDINAL);
(* jump forward, build chain. *)
BEGIN
(* MC68000 does NOT have a "Branch on Never True" ! *)
IF cond = F THEN Put16(CMPI) ELSE Put16(BRA + CodeCC(cond)*LS8) END;
Put16(l);
l := pc - 2; (* location of word-displacement *)
END Jf;
PROCEDURE Jb(cond : Condition; l : CARDINAL);
(* jump backward, no chain. *)
VAR dd : CARDINAL; d : INTEGER;
BEGIN
d := VAL(INTEGER,l) - VAL(INTEGER,pc) - 2;
dd := VAL(CARDINAL,d);
IF (d >= -128) & (cond # F) THEN (* short branch *)
Put16(BRA + CodeCC(cond)*LS8 + (dd MOD 256))
ELSE
Jf(cond,dd)
END;
END Jb;
PROCEDURE Scc(cond : Condition; Dn : Register);
(* set D-Register according to condition. *)
BEGIN
Put16(ST + CodeCC(cond)*LS8 + DDIR + Dn);
Put16(NEG + byte*LS6 + DDIR + Dn);
END Scc;
PROCEDURE LoadCC(VAR x : Item);
(* convert from 'cocMd' to 'DregMd' while *)
(* generating conditional code. *)
VAR Dn : Register;
BEGIN
WITH x DO
GetReg(Dn,Dreg);
IF (Tjmp = 0) & (Fjmp = 0) THEN
Scc(InvertCC(CC), Dn);
(* transform 'cocMd' to 'DregMd' *)
SetregMd(x, Dn, booltyp);
wid := byte;
ELSE
Jf(CC, Fjmp);
FixLink(Tjmp);
Put16(MOVEQ + Dn*LS9 + 1);
Put16(BRA + 2);
FixLink(Fjmp);
Put16(MOVEQ + Dn*LS9 + 0);
(* transform 'cocMd' to 'DregMd' *)
SetregMd(x, Dn, booltyp);
wid := long;
END;
END (*WITH*);
END LoadCC;
PROCEDURE ExternalCall(mno, pno : CARDINAL);
(* call of the external procedure #pno in module #mno. *)
VAR An : Register;
BEGIN
GetReg(An,Areg); (* An IN { 8 .. 15 } *)
An := An MOD 8;
Put16(MOVEAL + An*LS9 + AOFF + SB); (* MOVEA.L (maxP+mno)*4(SB),An *)
Put16((maxP + mno)*4);
IF pno = 0 THEN
Put16(MOVEAL + An*LS9 + AIDR + An); (* MOVEA.L (An),An *)
ELSE
Put16(MOVEAL + An*LS9 + AOFF + An); (* MOVEA.L pno*4(An),An *)
Put16(pno*4);
END;
Put16(JSR + AIDR + An); (* JSR (An) *)
ReleaseReg(An + 8);
END ExternalCall;
PROCEDURE downlevel(VAR x : Item);
(* for level difference >= 1. *)
CONST offSL = 8; (* offset of Static Link *)
VAR N,An : Register; n : CARDINAL;
BEGIN
GetReg(N,Areg); (* N IN { 8..15 } *)
An := N MOD 8;
Put16(MOVEAL + An*LS9 + AOFF + MP); (* MOVEA.L offSL(MP),An *)
Put16(offSL);
n := curLev - x.lev;
WHILE n > 1 DO
DEC(n);
Put16(MOVEAL + An*LS9 + AOFF + An); (* MOVEA.L offSL(An),An *)
Put16(offSL);
END;
ReleaseReg(x.R);
x.R := N;
END downlevel;
PROCEDURE Ext(VAR x : Item);
(* effective address extension of x. *)
VAR ext : CARDINAL; sz : INTEGER;
BEGIN
WITH x DO
CASE mode OF
absMd : Put32(adr);
| RindMd : IF adr <> 0 THEN Put16(adr) END;
| RidxMd : IF wid = word THEN ext := RX*LS12 + scl*LS9
ELSE ext := RX*LS12 + LS11 + scl*LS9 END;
Put16(ext + (VAL(CARDINAL,adr) MOD 256));
| conMd : IF typ = stringtyp THEN
Put16(val.D0+VAL(INTEGER, maxP+maxM)*4)
ELSE sz := typ^.size;
IF sz = 1 THEN Put16(WordVal(x))
ELSIF sz = 2 THEN Put16(WordVal(x))
ELSIF sz = 4 THEN Put32(LongVal(x))
ELSIF sz = 8 THEN
Put16(val.D0); Put16(val.D1);
Put16(val.D2); Put16(val.D3);
END;
END;
| stkMd : (* no extension *)
| AregMd,DregMd : (* no extension *)
| procMd : IF (proc <> NIL) & (proc^.pd <> NIL) &
(proc^.pd^.adr <> 0) THEN
(* local procedure *)
Put16(proc^.pd^.adr - VAL(INTEGER,pc));
ELSE (* external procedure *)
(* no extension *)
END;
| prgMd : Put16(VAL(INTEGER,where) - VAL(INTEGER,pc));
| typMd,codMd : (* no extension *)
| cocMd,fltMd : (* no extension *)
END (*CASE*);
END (*WITH*);
END Ext;
PROCEDURE ReduceIndir(VAR x : Item; ea : CARDINAL);
(* Note : A-Registers internally numbered from 8 .. 15! *)
VAR src, dst : Register;
BEGIN
WITH x DO
CASE mode OF
absMd :
GetReg(dst,Areg);
Put16(MOVEAL + (dst MOD 8)*LS9 + ea);
Ext(x);
| RindMd,RidxMd :
src := R;
IF Islocked(src) THEN GetReg(dst,Areg)
ELSE dst := src END;
Put16(MOVEAL + (dst MOD 8)*LS9 + ea);
Ext(x);
IF dst <> src THEN ReleaseReg(src) END;
IF mode = RidxMd THEN ReleaseReg(RX) END;
END (*CASE*);
(* transform all modes to 'RindMd' *)
mode := RindMd; R := dst; (* R IN { 8..15 } *)
indir := FALSE; adr := off; off := 0;
END (*WITH*);
END ReduceIndir;
PROCEDURE GeaP(VAR x : Item; VAR fea : CARDINAL);
(* effective address of an item designating a procedure. *)
VAR An : Register;
BEGIN
WITH x DO
IF (proc <> NIL) & (proc^.pd <> NIL) &
(proc^.pd^.adr <> 0) THEN (* local procedure *)
fea := PREL;
ELSE (* external procedure *)
GetReg(An,Areg);
Put16(MOVEAL + (An MOD 8)*LS9 + AOFF + SB);
Put16((maxP + VAL(CARDINAL,proc^.pmod))*4);
Put16(MOVEAL + (An MOD 8)*LS9 + AOFF + (An MOD 8));
Put16(proc^.pd^.num*4);
(* transform 'procMd' to 'AregMd' *)
SetregMd(x, An, typ);
fea := ADIR + (An MOD 8);
END;
END (*WITH*);
END GeaP;
PROCEDURE Gea(VAR x : Item; VAR fea : CARDINAL);
(* give effective address of x. *)
VAR ea : CARDINAL; An : Register;
BEGIN
WITH x DO
CASE mode OF
absMd : ea := XXXL;
| RindMd : IF R = (MP + 8) THEN
IF lev <> curLev THEN downlevel(x) END;
END;
IF adr <> 0 THEN ea := AOFF + (R MOD 8)
ELSE ea := AIDR + (R MOD 8) END;
| RidxMd : IF (-128 <= adr) & (adr <= 127) THEN
ea := AIDX + (R MOD 8)
ELSE (* adr out of 8-bit range *)
IF Islocked(R) THEN GetReg(An,Areg)
ELSE An := R END;
Put16(LEA + (An MOD 8)*LS9 + AIDX + (R MOD 8));
IF wid = word THEN Put16(RX*LS12 + scl*LS9)
ELSE Put16(RX*LS12 + LS11 + scl*LS9) END;
IF R <> An THEN ReleaseReg(R) END;
ReleaseReg(RX);
(* transform 'RidxMd' to 'RindMd' *)
mode := RindMd; ea := AOFF + (An MOD 8);
R := An;
END (*RidxMd*);
| conMd : IF typ = stringtyp THEN
ea := AOFF + SB (* SB-relative *)
ELSE
ea := IMM (* for all sizes *)
END;
| stkMd : ea := AINC + SP; (* gives (SP)+ *)
| AregMd : ea := ADIR + (R MOD 8);
| DregMd : ea := DDIR + (R MOD 8);
| prgMd : ea := PREL;
| typMd, codMd : ea := DDIR + D0; (* dummy effective address *)
err(232); (* NO address equivalent ! *)
| procMd, cocMd,
fltMd : ea := DDIR + D0; (* dummy effective address *)
err(233); (* should never occur here!*)
END (*CASE*);
IF (mode < conMd) & indir THEN
ReduceIndir(x,ea);
IF adr <> 0 THEN ea := AOFF + (R MOD 8)
ELSE ea := AIDR + (R MOD 8) END;
END;
END (*WITH*);
fea := ea ; (* resulting effective address *)
END Gea;
PROCEDURE OvflTrap(signed : BOOLEAN);
(* overflow-check thru TRAPV for signed arithmetic : *)
BEGIN
IF NOT ovflchk THEN RETURN END;
IF signed THEN Put16(TRAPV) END;
END OvflTrap;
PROCEDURE OvflCheck(R : Register; signed : BOOLEAN);
(* overflow-check for 16*16bit signed multiplication : *)
VAR Dn : Register;
BEGIN
IF NOT ovflchk THEN RETURN END;
IF signed THEN
GetReg(Dn,Dreg); (* scratch reg. *)
Put16(MOVEW + Dn*LS9 + R); (* copy wordpart *)
Put16(EXTL + Dn); (* EXT.L Dn *)
Put16(CMP + R*LS9 + long*LS6 + Dn); (* CMP.L Dn,R *)
Put16(BEQ + 6); (* BEQ.S 6 *)
Put16(ORI + IMM); (* ORI.W #VBIT,SR*)
Put16(VBIT);
Put16(TRAPV); (* TRAPV *)
ReleaseReg(Dn);
END;
END OvflCheck;
PROCEDURE StackTop(i : INTEGER);
(* increment/decrement stack pointer SP : *)
(* i > 0 : increment SP, reset stack *)
(* i < 0 : decrement SP, reserve stack *)
VAR neg : BOOLEAN; c : CARDINAL;
BEGIN
IF i <> 0 THEN
neg := (i < 0);
IF ODD(i) THEN
IF neg THEN DEC(i) ELSE INC(i) END;
END;
IF (-8 <= i) & (i <= 8) THEN
c := (VAL(CARDINAL,ABS(i)) MOD 8)*LS9;
IF neg THEN Put16(DECSP + c)
ELSE Put16(INCSP + c) END;
ELSE
Put16(LEASP);
Put16(i);
END;
END (*i <> 0*);
END StackTop;
PROCEDURE SetupSL(plev : CARDINAL);
(* push Static Link onto stack. *)
CONST offSL = 8; (* offset of Static Link relative to MP *)
VAR N, An : Register; n : CARDINAL;
BEGIN
IF plev <> 0 THEN
IF plev = curLev THEN
(* level difference = 0 *)
Put16(PEA + AIDR + MP); (* PEA (MP) *)
ELSIF plev + 1 = curLev THEN
(* level difference = 1 *)
Put16(MVEMSP + AOFF + MP); (* MOVE.L offSL(MP),-(SP) *)
Put16(offSL);
ELSE
(* level difference >= 2 *)
GetReg(N,Areg); An := N MOD 8;
Put16(MOVEAL + An*LS9 + AOFF + MP); (* MOVEA.L offSL(MP),An *)
Put16(offSL);
n := curLev - plev;
WHILE n > 2 DO
DEC(n);
Put16(MOVEAL + An*LS9 + AOFF+An); (* MOVEA.L offSL(An),An *)
Put16(offSL);
END;
Put16(MVEMSP + AOFF + An); (* MOVE.L offSL(An),-(SP) *)
Put16(offSL);
ReleaseReg(N);
END;
END (*plev <> 0*);
END SetupSL;
PROCEDURE InitM2HM;
VAR k : CARDINAL; exp : LONGINT;
BEGIN
curLev := 0;
MoveCode[byte] := MOVEB; MoveCode[word] := MOVEW;
MoveCode[long] := MOVEL;
ShiCode [Asl] := ASL; ShiCode [Asr] := ASR;
ShiCode [Lsl] := LSL; ShiCode [Lsr] := LSR;
ShiCode [Rol] := ROL; ShiCode [Ror] := ROR;
exp := 0D; mask[0] := 0D; mask[32] := -1D;
FOR k := 1 TO 31 DO exp := exp + exp + 1D; mask[k] := exp END;
IF DynArrDesSize = 6 THEN hightyp := inttyp
ELSE hightyp := dbltyp END;
InitRegs;
END InitM2HM;
PROCEDURE LoadAdr(VAR x : Item);
(* ADR(x) --->>> pointer/address-register. *)
VAR ea, am : CARDINAL; An : Register; newA, loaded : BOOLEAN;
BEGIN
WITH x DO
IF (mode IN ItSet{stkMd,AregMd,DregMd,cocMd,typMd,codMd,fltMd})
OR ((mode = conMd) & (typ <> stringtyp)) THEN
err(231); (* no effective address possible *)
Release(x); SetregMd(x, A0+8, undftyp);
END;
IF mode = procMd THEN GeaP(x,ea) ELSE Gea(x,ea) END;
am := (ea DIV 8)*8;
newA := TRUE; loaded := FALSE;
IF mode IN ItSet{RindMd,RidxMd,AregMd} THEN
IF NOT Islocked(R) THEN newA := FALSE END;
END;
IF newA THEN GetReg(An,Areg)
ELSE An := R;
IF (am = ADIR) OR (am = AIDR) THEN loaded := TRUE END;
END;
IF NOT loaded THEN
Put16(LEA + (An MOD 8)*LS9 + ea);
Ext(x);
END;
IF mode IN ItSet{RindMd,RidxMd,AregMd} THEN
IF newA THEN ReleaseReg(R) END;
END;
IF mode = RidxMd THEN ReleaseReg(RX) END;
(* resulting mode is 'AregMd'. *)
SetregMd(x, An, typ);
END (*WITH*);
END LoadAdr;
PROCEDURE Move(VAR x, y : Item);
(* *)
(* move simple type x --->>> simple type y *)
(* simple type means : item of size byte/word/long. *)
(* *)
VAR op, ea1, ea2 : CARDINAL; lv : LONGINT;
cload, domove : BOOLEAN; szx, szy : WidType;
BEGIN
IF x.mode = cocMd THEN LoadCC(x) END;
Isz(y,szy); Isz(x,szx);
Gea(x,ea1); Gea(y,ea2);
cload := (x.mode = conMd); domove := TRUE;
IF cload THEN lv := LongVal(x) END;
IF y.mode = DregMd THEN
(* load to D-Register : *)
ea2 := (y.R MOD 8)*LS9;
IF cload THEN
(* constant load to D-Register : *)
IF (lv >= -128D) & (lv <= 127D) THEN
Put16(MOVEQ + ea2 + (VAL(CARDINAL, WordVal(x)) MOD 256));
ELSIF (szx <= word) THEN
Put16(MOVEW + ea2 + IMM);
Put16(WordVal(x));
ELSE
Put16(MOVEL + ea2 + IMM);
Put32(lv);
END;
ELSE
(* variable load to D-Register : *)
IF x.mode = DregMd THEN domove := (x.R <> y.R) END;
IF (x.mode = AregMd) & (szy < long) THEN szy := long END;
op := MoveCode[szy];
IF domove THEN
Put16(op + ea2 + ea1);
Ext(x); (* source effective address extension *)
END;
END;
y.wid := szy;
ELSIF y.mode = AregMd THEN
(* load to A-Register : always sign extends the data. *)
ea2 := (y.R MOD 8)*LS9;
IF cload THEN
(* constant load to A-Register : always load long. *)
IF (lv >= -32768D) & (lv <= 32767D) THEN
Put16(MOVEAW + ea2 + IMM);
Put16(WordVal(x));
ELSE
Put16(MOVEAL + ea2 + IMM);
Put32(lv);
END;
ELSE
(* variable load to A-Register : *)
IF x.mode = AregMd THEN domove := (x.R <> y.R) END;
IF x.mode = DregMd THEN szy := x.wid END;
IF szy = byte THEN err(293) END;
op := MoveCode[szy] + ADIR*LS3;
IF domove THEN
Put16(op + ea2 + ea1);
Ext(x); (* source extension *)
END;
END;
ELSE
(* move to memory : *)
IF (x.mode = AregMd) & (szy < long) THEN err(292) END;
IF (y.mode = stkMd) THEN
(* destination on top of stack : gives -(SP). *)
ea2 := ADEC + SP;
SetstkMd(y, y.typ);
END;
IF cload & (lv = 0D) THEN
Put16(CLR + szy*LS6 + ea2);
Ext(y); (* extend destination *)
ELSIF (x.mode <> stkMd) OR (y.mode <> stkMd) THEN
op := MoveCode[szy] + Iea(ea2)*LS6 + ea1;
Put16(op);
Ext(x); (* extend source *)
Ext(y); (* extend destination *)
END;
END;
END Move;
PROCEDURE LoadD(VAR x : Item);
(* load simple type x to a D-Register. *)
VAR y : Item; Dn : Register;
BEGIN
WITH x DO
IF mode < DregMd THEN
GetReg(Dn,Dreg);
SetregMd(y, Dn, typ);
Move(x,y);
Release(x);
x := y;
ELSIF mode = cocMd THEN LoadCC(x)
ELSIF mode > DregMd THEN
err(230); Release(x);
SetregMd(x, D0, typ);
END;
END (*WITH*);
END LoadD;
PROCEDURE CheckPointer(VAR x : Item);
(* check x to be a non-NIL pointer *)
BEGIN
IF NOT(rngchk) OR (x.typ = addrtyp) THEN RETURN END;
LoadD(x);
Put16(BNE + 12); (* if NOT NIL-pointer *)
GenHalt(5); (* halt if NIL-pointer *)
END CheckPointer;
PROCEDURE LoadP(VAR x : Item);
(* load simple type or pointer to a pointer/address-register. *)
VAR y : Item; An : Register;
BEGIN
WITH x DO
IF (mode IN ItSet{RindMd,RidxMd}) & NOT(Islocked(R)) THEN
SetregMd(y, R, typ);
Move(x,y);
SetbusyReg(R); (* do NOT release register R *)
IF mode = RidxMd THEN ReleaseReg(RX) END;
x := y;
ELSIF (mode < AregMd) OR (mode = DregMd) THEN
GetReg(An,Areg);
SetregMd(y, An, typ);
Move(x,y);
Release(x);
x := y;
ELSIF (mode <> AregMd) THEN
err(230); Release(x);
SetregMd(x, A0+8, typ);
END;
END (*WITH*);
END LoadP;
PROCEDURE LoadX(VAR x : Item; req : WidType);
(* load simple type x to a D-Register and *)
(* sign extend it to the width given by req. *)
VAR y : Item; Dn : Register; sz : WidType;
cload, signar : BOOLEAN; lv : LONGINT;
PROCEDURE NewLoadX(VAR old, new : Item);
BEGIN
GetReg(Dn,Dreg);
SetregMd(new, Dn, old.typ);
IF NOT(signar) & (sz < req) & (sz < long) THEN
Put16(MOVEQ + Dn*LS9);
END;
Move(old,new);
Release(old);
IF signar & (sz < req) & (sz < long) THEN
IF sz = byte THEN Put16(EXTW + Dn) END;
IF req = long THEN Put16(EXTL + Dn) END;
END;
new.wid := req;
END NewLoadX;
BEGIN (* LoadX *)
IF x.mode = cocMd THEN LoadCC(x) END;
Isz(x,sz);
cload := SimpleC(x); (* Real constants not included *)
signar := SignedT(x);
WITH x DO
IF cload THEN
(* constants always loaded to long width. *)
lv := LongVal(x);
GetReg(Dn,Dreg); SetregMd(y, Dn, typ);
IF (lv >= -128D) & (lv <= 127D) THEN
Put16(MOVEQ + Dn*LS9 + (VAL(CARDINAL, WordVal(x)) MOD 256));
ELSE (* not quick *)
Put16(MOVEL + Dn*LS9 + IMM);
Put32(lv);
END;
y.wid := req; (* long satisfies req anyway *)
x := y;
ELSIF (mode = DregMd) THEN
(* x is already in a D-Register. *)
IF wid < req THEN
IF req = word THEN
IF sz = byte THEN
IF signar THEN Put16(EXTW + R)
ELSE (* unsigned types *)
Put16(ANDI + word*LS6 + R);
Put16(377B);
END;
END;
ELSIF req = long THEN
IF signar THEN
IF sz < long THEN
IF sz = byte THEN Put16(EXTW + R) END;
Put16(EXTL + R);
END;
ELSE (* unsigned types *)
IF sz < long THEN
Put16(ANDI + long*LS6 + R);
IF sz = byte THEN Put32(255D) ELSE Put32(65535D) END;
END;
END;
END;
END (*wid < req*);
wid := req;
ELSIF (mode <= AregMd) THEN
(* Real constants fall into this variant. *)
NewLoadX(x,y);
x := y;
ELSE
err(230); Release(x);
SetregMd(x, D0, typ);
END;
END (*WITH*);
END LoadX;
PROCEDURE MoveAdr(VAR x, y : Item);
(* ADR(x) --->>> y *)
VAR op, src, dst : CARDINAL; o, s : StrPtr;
BEGIN
WITH x DO
o := typ; (* save original type of x *)
s := y.typ; (* save original type of y *)
IF (mode IN ItSet{stkMd,AregMd,DregMd,cocMd,typMd,codMd,fltMd})
OR ((mode = conMd) & (typ <> stringtyp)) THEN
err(231); (* no effective address possible *)
Release(x); SetregMd(x, A0+8, undftyp);
END;
IF y.mode = stkMd THEN (* push address of x *)
op := 0;
IF (mode < conMd) & indir & (off = 0) THEN
indir := FALSE; op := MVEMSP;
END;
IF mode = procMd THEN GeaP(x,src) ELSE Gea(x,src) END;
IF mode = AregMd THEN
op := MVEMSP; (* MOVE.L An,-(SP) *)
ELSIF op = 0 THEN
op := PEA;
END;
Put16(op + src);
Ext(x);
ELSE (* move address of x *)
IF (mode < conMd) & indir & (off = 0) THEN
indir := FALSE;
ELSE
LoadAdr(x);
END;
typ := addrtyp; y.typ := addrtyp;
Move(x,y);
IF y.mode = DregMd THEN y.wid := long END;
END;
typ := o; (* restore original type of x *)
y.typ := s; (* restore original type of y *)
END (*WITH*);
Release(x); (* release associated registers *)
END MoveAdr;
PROCEDURE MoveBlock(VAR x, y : Item; sz : INTEGER; isstring : BOOLEAN);
(* Move a block of 'sz' bytes from x to y. *)
(* *)
(* x.mode = stkMd : block comes from stack *)
(* y.mode = stkMd : block goes onto stack *)
(* *)
(* Dogma : the implementation below presumes *)
(* ----- that all arrays and records are *)
(* allocated on a Word-boundary. *)
(* *)
VAR hsz, op, src, dst : CARDINAL; z : Item; xmode : ItemMode;
BEGIN
IF (x.mode <> stkMd) OR (y.mode <> stkMd) THEN
xmode := x.mode; (* save original mode of source op. *)
IF y.mode = stkMd THEN
StackTop( - sz );
y.mode := RindMd; (* transform 'stkMd' to 'RindMd' *)
END;
IF x.mode = stkMd THEN
x.mode := RindMd; (* transform 'stkMd' to 'RindMd' *)
END;
LoadAdr(x); src := AINC + (x.R MOD 8);
LoadAdr(y); dst := AINC + (y.R MOD 8);
op := MOVEB; hsz := sz;
IF NOT isstring THEN
(* Note : always byte - move for Strings due to DBEQ! *)
IF (hsz MOD 4) = 0 THEN op := MOVEL; hsz := hsz DIV 4
ELSIF (hsz MOD 2) = 0 THEN op := MOVEW; hsz := hsz DIV 2
END;
END;
op := op + Iea(dst)*LS6 + src;
IF hsz = 1 THEN Put16(op)
ELSIF hsz = 2 THEN Put16(op); Put16(op)
ELSIF hsz = 3 THEN Put16(op); Put16(op); Put16(op)
ELSIF hsz > 0 THEN
SetconMd(z, hsz - 1, inttyp);
LoadD(z);
Put16(op);
IF isstring THEN Put16(DBEQ + z.R)
ELSE Put16(DBRA + z.R) END;
Put16(177774B);
ReleaseReg(z.R);
END;
IF xmode = stkMd THEN StackTop( sz ) END;
END;
END MoveBlock;
PROCEDURE ConvertTyp(functyp : StrPtr; VAR x : Item);
VAR fs, xs : INTEGER; szf, szx : WidType; y : Item;
BEGIN
SetregMd(y, D0, functyp); (* dummy for SimpleT *)
WITH x DO
fs := functyp^.size;
xs := typ^.size;
IF fs <> xs THEN
IF SimpleT(x) & SimpleT(y) THEN
Isz(x,szx); Isz(y,szf);
IF mode = conMd THEN
SetconMd(x, LongVal(x), functyp);
ELSIF (mode <= DregMd) OR (mode = cocMd) THEN
IF szf <= szx THEN LoadD(x)
ELSE LoadX(x,szf) END;
ELSE err(81); Release(x);
END;
ELSE err(81); Release(x);
END;
END;
typ := functyp; (* type of x IS changed ! *)
IF (mode = DregMd) & SimpleT(y) THEN Isz(y,wid) END;
END (*WITH*);
END ConvertTyp;
PROCEDURE CallSystem(sysp : CARDINAL);
(* call System.#sysp where sysp = ordinal of procedure. *)
BEGIN
ExternalCall(maxM - 1, sysp);
END CallSystem;
PROCEDURE GenHalt(haltindex : CARDINAL);
BEGIN
haltindex := haltindex MOD 256;
IF (haltindex <> 0) & NOT(rngchk) THEN RETURN END;
Put16(MOVEQ + D0*LS9 + haltindex);
CallSystem(HALTX);
END GenHalt;
PROCEDURE Int32Ari(inst : CARDINAL; VAR x, y : Item);
(* Interface to the 32-Bit arithmetic in System. *)
(* x (inst) y ---->>> (D0.L,D1.L) *)
VAR yy : Item;
BEGIN
SetregMd(yy, D1, dbltyp); y.typ := dbltyp;
Put16(MOVEL + x.R); (* keep x.R reserved *)
Move(y,yy);
Release(y); (* let go y's registers *)
CallSystem(inst);
(* result in register-pair (D0.L,D1.L). *)
(* x.wid := long; *)
END Int32Ari;
PROCEDURE Op1(op : CARDINAL; VAR x : Item);
(* generate instructions with 1 operand represented *)
(* by an eff. address in bits [0..5] and its variable *)
(* size in bits [6..7] of the instruction word. *)
(* Used for CLR, TST, NEG, COM (=NOT), INC1, DEC1. *)
(* Not used for JSR, JMP, PEA, Scc because these *)
(* instructions have a fixed size. *)
(* Note : x can be a memory location or on TOS. *)
VAR ea : CARDINAL; sz : WidType;
BEGIN
Isz(x,sz);
Gea(x,ea);
WITH x DO
IF mode = stkMd THEN
(* change (SP)+ to (SP). *)
(* for TST the operand is popped from stack! *)
IF op <> TST THEN ea := AIDR + SP END;
END;
Put16(op + sz*LS6 + ea);
Ext(x);
IF mode = DregMd THEN wid := sz END;
END (*WITH*);
END Op1;
PROCEDURE Power2(VAR x : Item; VAR exp2 : CARDINAL) : BOOLEAN;
(* Note : negative numbers must NOT return as power of 2. *)
VAR pw2 : BOOLEAN;
v : LONGINT;
BEGIN
exp2 := 0; pw2 := FALSE;
IF SimpleC(x) THEN
v := LongVal(x);
pw2 := (v >= 1D); (* 1 = 2**0 *)
WHILE (v > 1D) & pw2 DO
pw2 := NOT ODD(v);
v := SHIFT(v, -1); (* v := v DIV 2D; *)
INC(exp2); (* side effect of Power2 *)
END;
END;
RETURN pw2 (* 0 <= exp2 <= 31 *)
END Power2;
PROCEDURE MulPw2(VAR x : Item; exp : CARDINAL; ovfl : BOOLEAN);
(* x * (power of 2) *)
(* relevant is the width, not the size! *)
VAR op : CARDINAL; Dn : Register;
BEGIN
IF exp <> 0 THEN
IF SignedT(x) THEN op := ASL ELSE op := LSL END;
op := op + x.wid*LS6 + x.R;
IF exp IN {1..8} THEN (* immediate shift *)
Put16(op + (exp MOD 8)*LS9);
ELSE (* register by register shift *)
GetReg(Dn,Dreg);
Put16(MOVEQ + Dn*LS9 + exp);
Put16(op + Dn*LS9 + LS5);
ReleaseReg(Dn);
END;
IF ovfl THEN OvflTrap(SignedT(x)) END;
(* do not change x.wid *)
END (*exp <> 0*);
END MulPw2;
PROCEDURE MUL2(VAR x, y : Item; ovfl : BOOLEAN);
(* x * y --->> x *)
VAR op, ea, pw2 : CARDINAL; szx, szy : WidType;
signar, loady : BOOLEAN;
BEGIN
Isz(x,szx); Isz(y,szy);
signar := SignedT(x) OR SignedT(y);
loady := y.mode IN ItSet{AregMd,stkMd};
IF szx < long THEN (* szy < long expected *)
(* 16 * 16 bits *)
IF (szy = byte) OR loady THEN LoadX(y,word) END;
LoadX(x,word); (* assert DregMd for destination *)
IF Power2(y,pw2) THEN MulPw2(x,pw2,ovfl)
ELSE
IF signar THEN op := MULS ELSE op := MULU END;
Gea(y,ea);
Put16(op + x.R*LS9 + ea);
Ext(y);
x.wid := long;
IF ovfl THEN OvflCheck(x.R, signar) END;
END;
ELSE
(* 32 * 32 bits *)
IF (szy < long) OR loady THEN LoadX(y,long) END;
LoadX(x,long); (* assert DregMd for destination *)
IF Power2(y,pw2) THEN MulPw2(x,pw2,ovfl)
ELSE
IF signar THEN op := MULS32 ELSE op := MULU32 END;
Int32Ari(op,x,y);
IF ovfl THEN OvflTrap(signar) END;
(* 64-bit result is in D0.L/D1.L : *)
(* x.R remains reserved, x.wid remains long. *)
Put16(MOVEL + x.R*LS9 + D0);
END;
END;
Release(y);
END MUL2;
PROCEDURE SHI2(inst : CARDINAL; VAR x, y : Item);
(* shift left/right x by y. *)
VAR op, cv : CARDINAL; szx : WidType; lv : LONGINT; imm : BOOLEAN;
BEGIN
IF (x.mode = stkMd) & (y.mode = stkMd) THEN LoadD(y) END;
LoadD(x);
Isz(x,szx);
op := inst + szx*LS6 + x.R; (* register to be shifted *)
imm := FALSE;
IF SimpleC(y) THEN
lv := LongVal(y);
IF (lv >= 1D) & (lv <= 8D) THEN imm := TRUE END;
END;
IF imm THEN (* immediate shift : value 0 excluded *)
cv := VAL(CARDINAL, lv) MOD 8;
Put16(op + cv*LS9);
ELSE (* register by register shift *)
LoadD(y); (* load shift count *)
op := op + y.R*LS9 + LS5; (* indicates register shift *)
(* shift is modulo 64 : no chechs are made for *)
(* positive or negative values of shift count. *)
Put16(op);
END;
x.wid := szx; (* resulting width of D-Register *)
Release(y);
END SHI2;
PROCEDURE LOG2(inst : CARDINAL; VAR x, y : Item);
(* the logical operators AND, OR, EOR. *)
(* x AND y --->> x *)
(* x OR y --->> x *)
(* x EOR y --->> x *)
(* Note : x can be a memory location *)
(* or on top of stack. *)
VAR op, eax, eay : CARDINAL; szx, szy : WidType;
BEGIN
Isz(x,szx); Isz(y,szy);
Gea(x,eax);
IF x.mode = stkMd THEN eax := AIDR + SP (* gives (SP) *) END;
IF SimpleC(y) & (x.mode <> AregMd) THEN
(* ANDI / ORI / EORI *)
IF inst = ANDL THEN op := ANDI
ELSIF inst = ORL THEN op := ORI
ELSE op := EORI END;
Put16(op + szx*LS6 + eax);
Ext(y); (* source extension first *)
Ext(x); (* destination extension *)
ELSE
IF (x.mode = stkMd) & (y.mode = stkMd) THEN LoadD(y) END;
IF x.mode = AregMd THEN LoadD(x); Gea(x,eax) END;
op := inst + szx*LS6;
Gea(y,eay);
IF (x.mode = DregMd) & (inst <> EORL) THEN
(* destination is D-Register : *)
Put16(op + x.R*LS9 + eay);
Ext(y); (* source extension *)
ELSE
(* destination is memory location or inst = EOR. *)
(* assert source operand in D-Register. *)
LoadD(y);
IF (inst <> EORL) THEN
op := op + LS8;
END;
Put16(op + y.R*LS9 + eax);
Ext(x); (* destination extension *)
END;
END;
IF x.mode = DregMd THEN x.wid := szx END;
Release(y);
END LOG2;
PROCEDURE DivPw2(VAR x : Item; exp : CARDINAL; modulus : BOOLEAN);
VAR m : LONGINT; y : Item;
BEGIN
IF exp = 0 THEN (* DIV/MOD 1 *)
IF modulus THEN Release(x); SetconMd(x, 0D, x.typ) END;
(* else no change if x DIV 1 *)
ELSE
LoadD(x);
IF NOT modulus THEN (* DIV *)
SetconMd(y, exp, inttyp);
IF SignedT(x) THEN SHI2(ASR,x,y)
ELSE SHI2(LSR,x,y)
END;
ELSE (* MOD *)
m := mask[exp]; (* 2**exp - 1 *)
SetconMd(y, m, x.typ);
LOG2(ANDL,x,y);
END;
END;
(* x.wid is set by SHI2 and LOG2 *)
Release(y);
END DivPw2;
PROCEDURE DIV2(VAR x, y : Item; modulus : BOOLEAN);
(* x DIV/MOD y --->> x *)
VAR op, ea, pw2 : CARDINAL; szx, szy : WidType;
signar, loady : BOOLEAN;
BEGIN
Isz(x,szx); Isz(y,szy);
signar := SignedT(x) OR SignedT(y);
loady := y.mode IN ItSet{AregMd,stkMd};
IF szx < long THEN (* szy < long expected *)
(* 32 DIV/MOD 16 bits *)
IF (szy = byte) OR loady THEN LoadX(y,word) END;
IF NOT(signar) & Power2(y,pw2) THEN DivPw2(x,pw2,modulus)
ELSE (* extend destination to 32 bits *)
LoadX(x,long); (* assert DregMd for destination *)
IF signar THEN op := DIVS ELSE op := DIVU END;
Gea(y,ea);
Put16(op + x.R*LS9 + ea);
Ext(y); (* extend the source *)
OvflTrap(signar); (* for security reasons *)
(* quotient in bits [0..15], remainder in bits [16..31] *)
IF modulus THEN Put16(SWAP + x.R) END;
x.wid := word; (* resulting width *)
END;
ELSE
(* 32 DIV/MOD 32 bits *)
IF (szy < long) OR loady THEN LoadX(y,long) END;
IF NOT(signar) & Power2(y,pw2) THEN DivPw2(x,pw2,modulus)
ELSE
LoadX(x,long); (* assert DregMd for destination *)
IF signar THEN op := DIVS32 ELSE op := DIVU32 END;
Int32Ari(op,x,y);
(* quotient in register D0.L, remainder in D1.L : *)
(* x.R remains reserved, x.wid remains long. *)
op := MOVEL + x.R*LS9;
IF modulus THEN Put16(op + D1) ELSE Put16(op + D0) END;
END;
END;
Release(y);
END DIV2;
PROCEDURE ADD2(inst : CARDINAL; VAR x, y : Item);
(* x + y --->> x *)
(* x - y --->> x *)
(* Note : x can be a memory location *)
(* or on top of stack. *)
VAR op, eax, eay : CARDINAL; szx, szy : WidType;
cadd : BOOLEAN; lv : LONGINT;
BEGIN
Isz(x,szx); Isz(y,szy);
Gea(x,eax);
IF x.mode = stkMd THEN eax := AIDR + SP (* gives (SP) *) END;
cadd := SimpleC(y);
IF cadd THEN lv := LongVal(y) END;
IF cadd & (x.mode <> AregMd) THEN
IF (lv >= 1D) & (lv <= 8D) THEN
IF inst = ADD THEN op := ADDQ ELSE op := SUBQ END;
eay := VAL(CARDINAL, lv) MOD 8;
Put16(op + eay*LS9 + szx*LS6 + eax);
Ext(x);
ELSIF (lv <> 0D) THEN
IF inst = ADD THEN op := ADDI ELSE op := SUBI END;
Put16(op + szx*LS6 + eax);
Ext(y); (* extend source constant first *)
Ext(x); (* extend destination *)
END;
ELSE
IF inst = ADD THEN op := ADD ELSE op := SUB END;
IF (x.mode = stkMd) & (y.mode = stkMd) THEN LoadD(y) END;
Gea(y,eay);
IF x.mode = DregMd THEN
(* destination is D-Register : *)
op := op + (x.R MOD 8)*LS9;
IF y.mode = AregMd THEN
(* allow word/long only for source in A-Reg. *)
IF szy = byte THEN err(288) END;
END;
Put16(op + szx*LS6 + eay);
Ext(y); (* extend source *)
ELSIF x.mode = AregMd THEN
(* destination is A-Register : *)
op := op + (x.R MOD 8)*LS9;
(* allow long operation only. *)
IF szx < long THEN err(287) END;
Put16(op + 700B + eay); (* 700B generates ADDA.L *)
Ext(y); (* extend source *)
ELSE
(* destination is memory location : *)
(* assert source op. in D-Register. *)
LoadD(y);
op := op + y.R*LS9 + LS8;
Put16(op + szx*LS6 + eax);
Ext(x); (* extend destination *)
END;
END;
IF x.mode = DregMd THEN x.wid := szx END;
Release(y);
END ADD2;
PROCEDURE Cmp2(VAR x, y : Item);
(* x - y *)
(* Note : x can be a memory location *)
(* or on top of stack. *)
VAR op, eax, eay : CARDINAL; szx, szy : WidType; lv : LONGINT;
BEGIN
Isz(x,szx); Isz(y,szy);
Gea(x,eax);
IF SimpleC(y) & NOT(x.mode IN ItSet{AregMd,conMd}) THEN
(* source is constant : *)
lv := LongVal(y);
IF lv = 0D THEN Op1(TST,x) (* x would be popped if stkMd *)
ELSE op := CMPI;
Put16(op + szx*LS6 + eax); (* x would be popped if stkMd *)
Ext(y); (* immediate source *)
Ext(x); (* extend destination *)
END;
ELSIF x.mode = AregMd THEN
(* destination is A-Register : *)
Gea(y,eay); op := CMP + (x.R MOD 8)*LS9;
(* allow long operation only. *)
IF szx < long THEN err(287) END;
Put16(op + 700B + eay); (* 700B generates CMPA.L *)
Ext(y); (* extend source *)
ELSE
(* destination must be D-Register : *)
IF (x.mode = stkMd) & (y.mode = stkMd) THEN LoadD(y) END;
LoadD(x);
Gea(y,eay); op := CMP + (x.R MOD 8)*LS9;
IF y.mode = AregMd THEN
(* allow word/long only for source in A-Reg. *)
IF szy = byte THEN err(288) END;
END;
Put16(op + szx*LS6 + eay); (* y would be popped if stkMd *)
Ext(y); (* extend source *)
END;
Release(y);
(* result is in the condition code register! *)
END Cmp2;
PROCEDURE In2(VAR x, y : Item);
(* perform bit-manipulations : BTST. *)
(* y is the destination bit pattern, *)
(* x is the bit number. *)
(* Caution : NEVER execute a BTST-instruction if *)
(* the bit number is greather than the width of the *)
(* set, because hardware takes count modulo 32. *)
VAR op : CARDINAL *)
(* *)
(* y is the shift count of type INTEGER *)
(* or CARDINAL. *)
(* if y >= 0 then shift LEFT. *)
(* if y < 0 then shift RIGHT. *)
(* *)
VAR op, ct, rm : CARDINAL; sz : WidType;
BEGIN
Isz(x,sz);
op := ShiCode[shiftop] + sz*LS6 + (x.R MOD 8); (* initially LEFT shift *)
IF y.mode = conMd THEN
(* immediate shift count : bit 5 remains 0! *)
ct := VAL(CARDINAL, WordVal(y));
IF VAL(INTEGER,ct) < 0 THEN
op := op - LS8; (* RIGHT shift *)
(* Note : overflow-checks must be OFF for compiler! *)
ct := ABS(VAL(INTEGER,ct));
END;
ct := ct MOD 32; (* shift count modulo 32 *)
rm := ct MOD 8; ct := ct DIV 8;
IF rm <> 0 THEN Put16(op + rm*LS9) END;
WHILE ct > 0 DO Put16(op); DEC(ct) END;
ELSE
(* variable shift count of type INTEGER/CARDINAL : *)
(* INTEGER/CARDINAL count treated the same way. *)
(* Note : Hardware takes shift count modulo 64 ! *)
LoadX(y,word); (* load shift count *)
op := op + y.R*LS9 + LS5; (* register shift *)
Put16(TST + word*LS6 + y.R); (* test shift count *)
Put16(BPL + 6); (* if count >= 0 *)
Put16(NEG + word*LS6 + y.R); (* abs. value count *)
Put16(op - LS8); (* RIGHT shift *)
Put16(BRA + 2); (* skip next instr. *)
Put16(op); (* LEFT shift *)
END;
x.wid := sz; (* resulting width of D-Register *)
Release(y);
END Ash2;
PROCEDURE ConIndex(VAR x : Item; inc : INTEGER);
(* called for constant index and field-offset. *)
(* if NOT indir : adr-field is incremented *)
(* if indir : off-field is incremented. *)
VAR i : INTEGER;
BEGIN
WITH x DO
IF mode < conMd THEN
(* reference to indir, adr, off allowed. *)
IF NOT indir THEN i := adr ELSE i := off END;
IF (i >= 0) & (inc <= MaxInt - i)
OR (i < 0) & (inc >= MIN(INTEGER) - i) THEN
i := i + inc;
IF NOT indir THEN adr := i ELSE off := i END;
ELSE (* offset overflow *)
LoadAdr(x); mode := RindMd; (* transform 'AregMd' to 'RindMd' *)
adr := inc;
END;
ELSE (* all other modes *)
err(235);
END;
END (*WITH*);
END ConIndex;
PROCEDURE Normalize(VAR x : Item; i : INTEGER);
(* normalize x with the low-bound i *)
VAR op : CARDINAL; y : Item;
BEGIN
IF i <> 0 THEN
(* Note : overflow-checks must be OFF for compiler! *)
IF i > 0 THEN op := SUB ELSE op := ADD; i := ABS(i) END;
SetconMd(y, i, x.typ);
ADD2(op,x,y);
END;
END Normalize;
PROCEDURE CheckHigh(VAR x, high : Item);
(* check item associated with x to be in the *)
(* range indicated by [ 0.. (high) ]. *)
(* Note : CHK treats operand and upper-bound *)
(* as signed 2's complement integers! *)
VAR ea : CARDINAL; sz, hsz : WidType;
BEGIN
IF NOT rngchk THEN RETURN END;
LoadD(x); (* assert x to be loaded into a D-register *)
Isz(high,hsz); Isz(x,sz);
IF sz = word THEN (* use CHK-instruction *)
IF hsz <> word THEN LoadD(high) END;
Gea(high,ea);
Put16(CHK + x.R*LS9 + ea);
Ext(high);
ELSE (* use CMP-instruction *)
IF hsz <> sz THEN LoadX(high,sz) END;
Gea(high,ea);
Put16(CMP + x.R*LS9 + sz*LS6 + ea);
Ext(high);
Put16(BLS + 4);
Put16(CHK + x.R*LS9 + IMM); (* trap always *)
Put16(-1);
END;
Release(high);
END CheckHigh;
PROCEDURE CheckClimit(VAR x : Item; limit : LONGINT);
(* check item associated with x to be in the *)
(* range indicated by [ 0 .. limit ]. *)
(* Note : Trap taken always if limit < 0. *)
(* CHK treats operand and upper-bound *)
(* as signed 2's complement integers! *)
VAR sz : WidType;
BEGIN
IF NOT rngchk THEN RETURN END;
IF (limit < 0D) THEN err(286) END; (* invalid limit *)
LoadD(x); (* assert x to be loaded into a D-register *)
Isz(x,sz);
IF sz = word THEN (* use CHK-instruction *)
Put16(CHK + x.R*LS9 + IMM);
Put16(VAL(INTEGER, limit));
ELSE (* use CMP-instruction *)
Put16(CMPI + sz*LS6 + x.R);
IF sz = long THEN Put32(limit)
ELSE Put16(VAL(INTEGER, limit));
END;
Put16(BLS + 4);
Put16(CHK + x.R*LS9 + IMM); (* trap always *)
Put16(-1);
END;
END CheckClimit;
PROCEDURE CheckRange(VAR x: Item; min, max, BndAdr: INTEGER);
(* check x in the constant range [ min .. max ] *)
VAR htyp : StrPtr; sz : WidType;
BEGIN
IF NOT rngchk THEN RETURN END;
IF SimpleT(x) THEN Isz(x,sz);
htyp := x.typ; (* hold original type of x *)
LoadX(x,word);
IF sz <= word THEN x.typ := inttyp END;
Normalize(x, min);
IF (max >= min) & ((min >= 0) OR (max <= (MaxInt + min))) THEN
max := max - min
ELSE
err(286); max := 0; (* range distance too big *)
END;
CheckClimit(x, max);
(* Note : overflow-checks must be OFF for compiler! *)
(* recover original value of x : *)
Normalize(x, - min);
x.typ := htyp; (* recover type of x *)
END;
END CheckRange;
PROCEDURE CheckDbltoSingle(VAR x, y : Item);
(* range check for assignment of double-word type x *)
(* to single-word type y (INTEGER/CARDINAL). *)
VAR Dn : Register;
BEGIN
IF NOT rngchk THEN RETURN END;
LoadD(x); (* load long x *)
GetReg(Dn,Dreg); (* scratch reg. *)
IF NOT SignedT(y) THEN
Put16(MOVEQ + Dn*LS9); (* MOVEQ #0,Dn *)
END;
Put16(MOVEW + Dn*LS9 + x.R); (* copy word part *)
IF SignedT(y) THEN
IF NOT SignedT(x) THEN (* Unsigned to Signed *)
Put16(BMI + 6); (* exclude values < 0 *)
END;
Put16(EXTL + Dn); (* EXT.L Dn *)
END;
Put16(CMP + x.R*LS9 + long*LS6 + Dn); (* CMP.L Dn,x.R *)
Put16(BEQ + 4); (* BEQ.S 4 *)
Put16(CHK + Dn*LS9 + IMM); (* CHK #-1,Dn *)
Put16(-1); (* trap always *)
ReleaseReg(Dn);
END CheckDbltoSingle;
PROCEDURE VarIndex(VAR x, y : Item; elsize : INTEGER);
(* generate x with a variable index y and elementsize elsize. *)
VAR elsz : Item; scale, pw2 : CARDINAL;
BEGIN
SetconMd(elsz, elsize, y.typ);
IF ~Power2(elsz,pw2) & (y.typ = dbltyp) THEN
y.typ := inttyp; (* force 16*16Bit MULS.W *)
SetconMd(elsz, elsize, y.typ);
END;
MUL2(y,elsz,FALSE); (* inhibit overflow-checks *)
scale := byte;
LoadAdr(x);
WITH x DO
(* transform 'AregMd' to 'RidxMd' *)
mode := RidxMd; indir := FALSE;
adr := 0; off := 0;
RX := y.R; wid := y.wid;
scl := scale;
END (*WITH*);
END VarIndex;
PROCEDURE GetHigh(VAR x : Item);
(* get high-index of dynamic array parameter : *)
(* *)
(* Caution : x.typ IS changed ! *)
(* ------- *)
BEGIN
WITH x DO
IF mode < conMd THEN
(* reference to indir, adr, off allowed. *)
indir := FALSE; off := 0;
adr := adr + 4; typ := hightyp;
ELSE err(240)
END;
END (*WITH*);
END GetHigh;
PROCEDURE PreLoad(VAR op : Symbol; VAR x , y : Item);
(* preload x and/or y for GenOp. *)
(* Note : No-operation for real types! *)
VAR z : Item;
BEGIN (* do nothing if x is not 'loadable' *)
IF NOT(SimpleT(x) & SimpleT(y)) THEN RETURN END;
IF (op = times) OR (op = plus) THEN
(* symmetric operators : *)
IF x.mode <> DregMd THEN
IF (y.mode = DregMd) & (y.R IN Rpool) THEN
z := x; x := y; y := z;
ELSE
IF (x.mode = conMd) & (y.mode <= stkMd) THEN
z := x; x := y; y := z;
END;
LoadD(x);
END;
(* else x already loaded *)
END;
ELSIF (op = div) OR (op = mod) THEN
(* a-symmetric operators : *)
(* 32bits / 16bits for DIVS/DIVU ! *)
LoadX(x,long);
ELSIF (op = slash) OR (op = minus) OR (op = rem) THEN
(* a-symmetric operators : *)
LoadD(x);
ELSIF (op >= eql) & (op <= geq) THEN
(* relational operators : *)
IF x.mode = conMd THEN
(* y.mode <> conMd ! *)
z := x; x := y; y := z;
IF op = lss THEN op := gtr
ELSIF op = leq THEN op := geq
ELSIF op = gtr THEN op := lss
ELSIF op = geq THEN op := leq
ELSE (* op := op *)
END;
END;
ELSE (* nothing for all other ops *)
END;
END PreLoad;
PROCEDURE DynArray (VAR x, y : Item);
(* generate descriptor for dynamic array parameters : *)
(* *)
(* Caution : guarantee HIGH to be in the range *)
(* ------- 0 <= HIGH <= MaxInt. *)
(* *)
CONST ByteSize = 1;
VAR high, onstack, e : Item; s : StrPtr;
i, elsize : INTEGER; dynbyte : BOOLEAN;
BEGIN
dynbyte := (x.typ^.ElemTyp = bytetyp);
IF (y.typ^.form = Array) THEN
elsize := y.typ^.ElemTyp^.size;
IF y.typ^.dyn THEN (* copy existing descriptor *)
high := y; GetHigh(high);
IF dynbyte & (elsize <> ByteSize) THEN
LoadD(high);
Inc1(high); (* enable overflow-check *)
SetconMd(e, elsize, high.typ);
MUL2(high,e,TRUE);
Op1(DEC1,high); (* disable overflow-check *)
IF ovflchk THEN CheckClimit(high, MaxInt - 1) END;
END;
ELSE (* generate new descriptor *)
IF NOT dynbyte THEN
s := y.typ^.IndexTyp; i := 0;
WITH s^ DO
IF form = Range THEN
IF (max >= min) & ((min >= 0) OR (max <= (MaxInt + min))) THEN
i := max - min
ELSE
err(286); (* range distance too big *)
END;
END (*Range*);
END (*WITH*);
ELSE
WITH y.typ^ DO
IF (form = Array) & (IndexTyp^.form = Range) & (elsize = 1) THEN
i := IndexTyp^.max - IndexTyp^.min;
ELSE
i := size; IF i > 0 THEN DEC(i) END;
END;
END;
END;
SetconMd(high, i, hightyp);
END;
ELSIF (y.typ^.form = String) THEN
i := y.val.D1; IF i > 0 THEN DEC(i) END;
SetconMd(high, i, hightyp);
ELSE
i := y.typ^.size; IF i > 0 THEN DEC(i) END;
SetconMd(high, i, hightyp);
IF y.mode >= conMd THEN err(231) END;
END;
SetstkMd(onstack, hightyp);
Move(high,onstack);
MoveAdr(y,onstack);
Release(high);
Release(y);
END DynArray;
PROCEDURE CopyDynArray(a, s : INTEGER);
(* descriptor at a(MP), element-size is s : *)
(* copy (high+1)*s Bytes from [a(MP)] on top *)
(* of stack and update descriptor address. *)
VAR Dn, An, Am : Register; op, src, dst : CARDINAL; x, e : Item;
BEGIN
SetlocMd(x, a+4, hightyp);
LoadD(x); Dn := x.R;
(* Caution : value of HIGH must be in positive INTEGER range, *)
(* ------- even if HIGH is hold in a longword (LONGINT) ! *)
(* this is essential for the code generation below. *)
Inc1(x); (* (high + 1) = nr. of elements *)
IF (s > 1) THEN (* (high + 1) * s = nr. of bytes to copy *)
SetconMd(e, s, x.typ);
MUL2(x,e,TRUE);
END;
IF ovflchk THEN CheckClimit(x, MaxInt - 1) END;
IF ODD(s) THEN
(* Note : Dn will never overflow at the INC below ! *)
Put16(BTST + LS11 - LS8 + Dn); (* total nr. of bytes *)
Put16(0); (* must be even *)
Put16(BEQ + 2); (* skip if already even *)
Put16(INC1 + word*LS6 + Dn); (* if VAR regs : LONGINT; y : Item; rtyp : StrPtr;
BEGIN
WITH x DO
SetfltMd(y, D0, typ); (* load into scratch D0/D1 *)
FMove(x,y);
Release(x);
x := y;
Release(x); (* so D0/D1 are NOT saved *)
SaveRegs(regs); (* save busy registers *)
CASE op OF
(* define resulting type *)
FNEGs, FABSs : rtyp := realtyp;
| FNEGd, FABSd : rtyp := lrltyp;
| TRUNCs, TRUNCd : rtyp := dbltyp;
| FLOATs, FSHORT : rtyp := realtyp;
| FLOATd, FLONG : rtyp := lrltyp;
END;
StackTop( - rtyp^.size ); (* space for function result *)
SetstkMd(y, typ);
FMove(x,y); (* push parameter onto stack *)
Release(x); (* now release the parameter *)
CallSystem(op); (* call the function in System *)
SetstkMd(x, rtyp); (* result on top of stack *)
IF regs <> 0D THEN (* saved regs above result *)
IF SimpleT(x) THEN LoadD(x)
ELSE LoadF(x) END;
RestoreRegs(regs); (* restore busy registers *)
END;
END (*WITH*);
END FOp1;
PROCEDURE FOp2(op : CARDINAL; VAR x, y : Item);
(* Interface to the SANE interface in module System *)
(* for dyadic Floating-Point-Operations. *)
VAR regs : LONGINT; z : Item; rtyp : StrPtr;
Regs : RECORD
CASE :BOOLEAN OF
TRUE : All : LONGINT
| FALSE: X,F,D,A : CHAR
END
END;
BEGIN
SetfltMd(z, D0, y.typ); (* load y into scratch D0/D1 *)
FMove(y,z); (* y must be loaded first (stkMd) *)
Release(y);
y := z;
Release(y); (* so D0/D1 are NOT saved *)
LoadF(x); (* load x into scratch Dn/Dn+1 *)
Release(x); (* so Dn/Dn+1 are NOT saved *)
SaveRegs(regs); (* save busy registers *)
CASE op OF
(* define resulting type *)
FADDs, FSUBs, FMULs, FDIVs, FREMs : rtyp := realtyp;
| FADDd, FSUBd, FMULd, FDIVd, FREMd : rtyp := lrltyp;
| FCMPs, FCMPd : rtyp := notyp;
END;
IF rtyp <> notyp THEN
StackTop( - rtyp^.size ); (* space for function result *)
END;
SetstkMd(z, x.typ);
FMove(x,z); (* push x-parameter onto stack *)
Release(x); (* now release the x-parameter *)
SetstkMd(z, y.typ);
FMove(y,z); (* push y-parameter onto stack *)
Release(y); (* now release the y-parameter *)
CallSystem(op); (* call the function in System *)
SetstkMd(x, rtyp); (* result on top of stack *)
IF regs <> 0D THEN (* saved regs above result *)
IF rtyp <> notyp THEN
LoadF(x) (* pop function result from stack *)
ELSE
(* Caution : for FCMPs/FCMPd result is in the CCR : *)
(* ------- avoid the restoring of a single D-Register *)
(* (eventually done by M2HM.RestoreRegs) *)
(* because this would destroy the CCR ! *)
Regs.All := regs; IF Regs.D <> 0C THEN err(244) END;
END;
RestoreRegs(regs); (* restore busy registers *)
END;
END FOp2;
PROCEDURE FMonad(op : FMonadic; VAR x : Item);
(* interface to the SANE monadic operators : *)
VAR cd : CARDINAL; y : Item;
BEGIN
cd := 0; (* indicates NO FOp1-call *)
CASE op OF
| Abs : cd := FABSs;
| NonStand : cd := FNEGs;
| Float : LoadX(x,long);
x.typ := realtyp; (* essential for FOp1! *)
FOp1(FLOATs,x);
| FloatD : LoadX(x,long);
x.typ := realtyp; (* essential for FOp1! *)
FOp1(FLOATd,x);
| Long : FOp1(FLONG,x);
| Short : FOp1(FSHORT,x);
| Trunc : IF x.typ <> realtyp THEN err(241) END;
FOp1(TRUNCs,x);
LoadD(x);
SetregMd(y, D0, inttyp);
CheckDbltoSingle(x,y);
| TruncD : IF x.typ <> lrltyp THEN err(239) END;
FOp1(TRUNCd,x);
LoadD(x);
ELSE err(200);
END (*CASE*);
IF cd <> 0 THEN
IF x.typ = lrltyp THEN INC(cd,10) (* take double precision *) END;
FOp1(cd,x);
END;
END FMonad;
PROCEDURE FDyad(op : FDyadic; VAR x, y : Item);
(* interface to the SANE dyadic operators : *)
VAR cd : CARDINAL;
BEGIN
cd := 0; (* indicates NO FOp2-call *)
CASE op OF
| plus : cd := FADDs;
| minus : cd := FSUBs;
| times : cd := FMULs;
| slash : cd := FDIVs; IF ZeroVal(y) THEN err(205) END;
| eql .. geq : cd := FCMPs;
ELSE err(200);
END (*CASE*);
IF cd <> 0 THEN
IF x.typ = lrltyp THEN INC(cd,10) (* take double precision *) END;
FOp2(cd,x,y);
END;
Release(y);
END FDyad;
END M2HM. (* Copyright Departement Informatik, ETH Zuerich, Switzerland, 1992 *)